#include "..\\include\Lib_Clara.h"
#include "..\\include\Dir.h"
#include "..\\include\cfg_items.h"
#include "config_data.h"
#include "conf_loader.h"
#include "struct.h"

#define A2_old 1
#define A2_new 2
#define DB2020 3

#define _GC_PutChar(_imgID_,_x_,_y_) GC_PutChar(gc,_x_,_y_,0,0,_imgID_)

#define COPYRIGHT_STR L"Interactive Music Widget\n(c)mc_kibel\n(r)Blacklizard [DB3150 player structure]"

#define MUSICWIDGET_GOT_FOCUS 0x3015
#define MUSICWIDGET_LOST_FOCUS 0x3016

enum MP_METHODS
{
  PLAY_PAUSE,
  NEXT_TRACK,
  SHOW
};

enum APPWIDGET_ICONS
{
  BG,
  HIGHLIGHTED,
  PLAY_NORMAL,
  PLAY_FOCUSED,
  PAUSE_NORMAL,
  PAUSE_FOCUSED,
  NEXT_NORMAL,
  NEXT_FOCUSED
};

enum MP3_TAGS
{
  TAG_ARTIST,
  TAG_TITLE,
  TAG_ALBUM,
  TAG_YEAR,
  TAG_GENRE
};

typedef struct
{
  BOOK * book;
}MSG;

void (*SIonRedraw)(DISP_OBJ *,int r1,int r2,int r3);

GC * gc;
DISP_OBJ *_do;
BOOK * myBook;
wchar_t *ttl;
wchar_t *artst;
u16 timer;

int MainInputLastLen = 0;
int pos = 1;
int focused = 0;
int platform = 0;
int fontsize;

int delay_counter = 0;  // Mmmm.... random reboots on DB3150 / DB3210. Maybe player is not ready with ID3 tags? So we should give it some time

wchar_t path[256] = {0,};

wchar_t UNK_ARTIST[] = L"Unknown artist";
wchar_t GETTING_TAGS[] = L"Getting tags";
wchar_t DOTS[] = L"...";

wchar_t *appwidget_icons[] = {
  //---------
  L"appwidget_bg.png",
  L"appwidget_high.png",
  //---------
  L"appwidget_play_normal.png",
  L"appwidget_play_focused.png",
  //---------
  L"appwidget_pause_normal.png",
  L"appwidget_pause_focused.png",
  //---------
  L"appwidget_next_normal.png",
  L"appwidget_next_focused.png"
  //---------
};

wchar_t appwidget_ids[] = {
  0xFFFF,
  0xFFFF,
  0xFFFF,  0xFFFF,  0xFFFF,
  0xFFFF,  0xFFFF,  0xFFFF,
};

int isInteractiveMusicWidgetBook(BOOK * book)
{
  if(!strcmp(book->xbook->name,"InteractiveMusicWidget")) 
    return 1;
  return 0;
}

void InitImages(void)
{
  for (int i = 0 ; i < sizeof(appwidget_ids) / 2 ; i++) ImageID_Get(path,appwidget_icons[i],&appwidget_ids[i]);
}

void DestroyImages(void)
{
  for (int i = 0 ; i < sizeof(appwidget_ids) / 2 ; i++) ImageID_Free(appwidget_ids[i]);
}

int _MainInput_getVisible( GUI * g )
{
  char c;
  DISP_OBJ* dispobj = GUIObject_GetDispObject( g ); 
  c = DispObject_GetVisible( dispobj );
  if (MainInputLastLen == 1)
  {
    MainInputLastLen = 0;
    c = 1;
  }
  return (c);
}

int isPlaying ()
{
  if (FindBook(get_IsAudioPlayerBook())) return 1;
  return 0;
}

void MP_Control (enum MP_METHODS mp)
{
  switch (mp)
  {
  case PLAY_PAUSE:
    GoMusic();
    break;
  case NEXT_TRACK:
    UI_Event(UI_MEDIAPLAYER_NEXT_TRACK_EVENT);
    break;
  case SHOW:
    Shortcut_Run(L"MediaPlayer");
    break;
  default:
    break;
  }
}

int OnKey (int key, int mode)
{
  if (key==KEY_UP || key==KEY_DOWN)
  {
    if (mode == KBD_SHORT_PRESS)
    {
      if (focused == 0)
      {
        focused = 1;
        // Sending an event to Deskbar elf to set it in inactive mode - it won't react on keys
        UI_Event (MUSICWIDGET_GOT_FOCUS);
      }
      else
      {
        focused = 0;
        // Now, sending event to 'wake' Deskbar
        UI_Event (MUSICWIDGET_LOST_FOCUS);
      }
      DispObject_InvalidateRect(_do,0);
    }
  }
  if (focused == 1)
  {
    if (key==KEY_LEFT && mode==KBD_SHORT_PRESS)
    {
      if (pos > 1) pos--;
      else pos = 3;
      DispObject_InvalidateRect(_do,0);
      return -1;
    }
    else if (key==KEY_RIGHT && mode==KBD_SHORT_PRESS)
    {
      if (pos < 3) pos++;
      else pos = 1;
      DispObject_InvalidateRect(_do,0);
      return -1;
    }
    else if (key==KEY_DEL && mode==KBD_SHORT_PRESS)
    {
      if (pos == 1) MP_Control(PLAY_PAUSE);
      else if (pos == 2) MP_Control(SHOW);
      else if (pos == 3) MP_Control(NEXT_TRACK);
      //DispObject_InvalidateRect(_do,0);
      return -1;
    }
  }
  return 0;
}

int WidgetKey (int key, int r1, int mode)
{
  if (Display_GetTopBook(0) == Find_StandbyBook())
  {
    if (MainInputLock == 1)
    {
      if (_MainInput_getVisible(SBY_GetMainInput(Find_StandbyBook()))==0)
        return (OnKey (key,mode));
      else
        MainInputLastLen = MainInput_strlen( SBY_GetMainInput(Find_StandbyBook()) );
    }
    else
      return (OnKey (key,mode));
  }
  return 0;
}

int isTagEmpty (wchar_t *tag)
{
  //It's not 100% correct method, but works 
  if (wstrlen(tag)==43) return 1;
  return 0;
}

void GetTags()
{
  //Function is called every second when music is in play state. So I gave extra 3 seconds for player to get ready.
  if (delay_counter > 2)
  {
    BOOK *bk = FindBook(get_IsAudioPlayerBook());
    wchar_t *path, *name;
    if (platform == DB2020)
    {
      BOOK_PLAYER_2020 *bkp=(BOOK_PLAYER_2020*)bk;
      path = bkp->dsc->path;
      name = bkp->dsc->name;
    }
    else if (platform == A2_new)
    {
      BOOK_PLAYER_3210 *player = (BOOK_PLAYER_3210*)FindBook(get_IsAudioPlayerBook());
      path = player->dsc->xdesc->fpath;
      name = player->dsc->xdesc->fname;
    }
    else if (platform == A2_old)
    {
      BOOK_PLAYER_3150 *player = (BOOK_PLAYER_3150*)FindBook(get_IsAudioPlayerBook());
      path = player->dsc->xdesc->fpath;
      name = player->dsc->xdesc->fname;
    }
    void *MetaData_Desc = MetaData_Desc_Create(path, name);
    ttl = MetaData_Desc_GetTags(MetaData_Desc,TAG_TITLE);
    artst = MetaData_Desc_GetTags(MetaData_Desc,TAG_ARTIST);
    MetaData_Desc_Destroy(MetaData_Desc);
    if (isTagEmpty(ttl)) ttl = name;
    if (isTagEmpty(artst)) artst = UNK_ARTIST;
  }
  else
  {
    ttl = GETTING_TAGS;
    artst = DOTS;
    delay_counter++;
  }
}

void DISP_OnRedraw(DISP_OBJ* DO,int a,int b,int c) 
{
  int title,artist;
  if (SIonRedraw) SIonRedraw(DO,a,b,c); 
  _GC_PutChar(appwidget_ids[BG],X_POS,Y_POS);
  if (isPlaying() == 1)
  {
    if (focused == 1)
    {
      if (pos == 1)
      {
        _GC_PutChar(appwidget_ids[NEXT_NORMAL],X_POS+204,Y_POS+33);
        _GC_PutChar(appwidget_ids[PAUSE_FOCUSED],X_POS+21,Y_POS+27);
      }
      else if (pos == 2)
      {
        _GC_PutChar(appwidget_ids[NEXT_NORMAL],X_POS+204,Y_POS+33);
        _GC_PutChar(appwidget_ids[PAUSE_NORMAL],X_POS+21,Y_POS+27);
        _GC_PutChar(appwidget_ids[HIGHLIGHTED],X_POS,Y_POS);
      }
      else if (pos == 3)
      {
        _GC_PutChar(appwidget_ids[NEXT_FOCUSED],X_POS+204,Y_POS+33);
        _GC_PutChar(appwidget_ids[PAUSE_NORMAL],X_POS+21,Y_POS+27);
      }
    }
    else
    {
      _GC_PutChar(appwidget_ids[NEXT_NORMAL],X_POS+204,Y_POS+33);
      _GC_PutChar(appwidget_ids[PAUSE_NORMAL],X_POS+21,Y_POS+27);
    }
    GetTags();
    title = Str2ID (ttl,0,SID_ANY_LEN);
    artist = Str2ID (artst,0,SID_ANY_LEN);
  }
  else
  {
    if (focused == 1)
    {
      if (pos == 1)
      {
        _GC_PutChar(appwidget_ids[NEXT_NORMAL],X_POS+204,Y_POS+33);
        _GC_PutChar(appwidget_ids[PLAY_FOCUSED],X_POS+20,Y_POS+24);
      }
      else if (pos == 2)
      {
        _GC_PutChar(appwidget_ids[NEXT_NORMAL],X_POS+204,Y_POS+33);
        _GC_PutChar(appwidget_ids[PLAY_NORMAL],X_POS+20,Y_POS+24);
        _GC_PutChar(appwidget_ids[HIGHLIGHTED],X_POS,Y_POS);
      }
      else if (pos == 3)
      {
        _GC_PutChar(appwidget_ids[NEXT_FOCUSED],X_POS+204,Y_POS+33);
        _GC_PutChar(appwidget_ids[PLAY_NORMAL],X_POS+20,Y_POS+24);
      }
    }
    else
    {
      _GC_PutChar(appwidget_ids[NEXT_NORMAL],X_POS+204,Y_POS+33);
      _GC_PutChar(appwidget_ids[PLAY_NORMAL],X_POS+20,Y_POS+24);
    }
    title = Str2ID (L"Music is turned off",0,SID_ANY_LEN);
    artist = Str2ID (L"Play",0,SID_ANY_LEN);
    delay_counter = 0;
  }
  SetFont(fontsize);
  {
    DrawString(title,0,X_POS+53,Y_POS+20,X_POS+198,Y_POS+40,0,0,0xFF000000,0xFF000000);
    DrawString(artist,0,X_POS+53,Y_POS+41,X_POS+198,Y_POS+58,0,0,0xFF000000,0xFF000000);
  }
  TextFree(title);
  TextFree(artist);
}
  
void elf_exit(void)
{
  kill_data(&ELF_BEGIN, (void(*)(void*))mfree_adr());
}

void Send_REDRAW_RELEASE()
{
  REDRAW_RELEASE_MESSAGE * sbm= new REDRAW_RELEASE_MESSAGE;
  memset(sbm,0,sizeof(REDRAW_RELEASE_MESSAGE));
  sbm->SB_OldOnRedraw=SIonRedraw;
  sbm->SB_NewOnRedraw=DISP_OnRedraw;
  UI_Event_wData(SBY_REDRAW_RELEASE_EVENT ,sbm,(void (*)(void*))mfree_adr());
}

static int TerminateElf(void * ,BOOK *book)
{
  FreeBook(book);
  return(1);
}

static int ShowAuthorInfo(void *mess ,BOOK *book)
{
  MSG * msg = (MSG *)mess;
  MessageBox(0x6FFFFFFF,Str2ID(COPYRIGHT_STR,0,SID_ANY_LEN),0, 1 ,0,msg->book);
  return(1);
}

static int ReconfigElf(void *mess ,BOOK *book)
{
  RECONFIG_EVENT_DATA *reconf=(RECONFIG_EVENT_DATA *)mess;
  int result=0;
  if (wstrcmpi(reconf->path,successed_config_path)==0 && wstrcmpi(reconf->name,successed_config_name)==0)
  {
    InitConfig();
  }
  return(result);
}

int SB_ELF_Killed(void *mess ,BOOK* book)
{
  REDRAW_RELEASE_MESSAGE * sbm=(REDRAW_RELEASE_MESSAGE*)mess;
  REDRAW_RELEASE_MESSAGE *res=0;
  if (sbm->SB_NewOnRedraw==SIonRedraw)
  {
    res=new REDRAW_RELEASE_MESSAGE;
    memcpy(res,sbm,sizeof(REDRAW_RELEASE_MESSAGE));
    if (sbm->SB_OldOnRedraw) SIonRedraw=sbm->SB_OldOnRedraw;
    DISP_DESC_SetOnRedraw(DispObject_GetDESC(_do),DISP_OnRedraw);
    res->SB_NewOnRedraw=DISP_OnRedraw;
    res->SB_OldOnRedraw=0;
  }
  if (res)
  {
    UI_Event_wData(SBY_REDRAW_RELEASE_EVENT ,res,(void (*)(void*))mfree_adr());
    return 1;
  }
  return 0;
}

const PAGE_MSG bk_msglst_base[] @ "DYN_PAGE"  = 
{
  SBY_REDRAW_RELEASE_EVENT,     SB_ELF_Killed,
  ELF_TERMINATE_EVENT,          TerminateElf,
  ELF_SHOW_INFO_EVENT,          ShowAuthorInfo,
  ELF_RECONFIG_EVENT,           ReconfigElf,
  NIL_EVENT_TAG,                NULL
};
const PAGE_DESC bk_base = {"IMW_BasePage",0,bk_msglst_base};

static void onMyBookClose(BOOK * book)
{
  UI_Event(MUSICWIDGET_LOST_FOCUS);
  DISP_DESC_SetOnRedraw(DispObject_GetDESC(_do),SIonRedraw);
  DispObject_InvalidateRect(_do,0);
  DestroyImages();
  ModifyKeyHook(WidgetKey,0);
  Timer_Kill(&timer);
  Send_REDRAW_RELEASE();
  SUBPROC(elf_exit);
}

void onTimer (u16 tmr , void *)
{
  DispObject_InvalidateRect(_do,0);
  Timer_ReSet(&timer,1000,onTimer,0);
}

int main(void)
{
  if (FindBook(isInteractiveMusicWidgetBook))
  {
    MessageBox(0x6FFFFFFF,STR("InteractiveMusicWidget is already working!"),0, 1 ,0,0);
    return 1;
  }
  myBook = new BOOK;
  memset( myBook, 0, sizeof( BOOK ) );
  CreateBook(myBook,onMyBookClose,&bk_base,"InteractiveMusicWidget",-1,0);
  wstrcpy (path,GetDir(MEM_INTERNAL | DIR_ELFS_CONFIG));
  wstrcat (path,L"/Widgets/Music/");
  int chip = GetChipID() & CHIPID_MASK;
  switch (chip)
  {
  case CHIPID_DB3150:
    platform = A2_old;
    fontsize = FONT_E_18R;
    break;
  case CHIPID_DB3200:
  case CHIPID_DB3210:
  case CHIPID_DB3350:
    platform = A2_new;
    fontsize = FONT_E_18R;
    break;
  default:
    platform = DB2020;
    fontsize = 0x19;
    break;
  }
  InitConfig();
  timer = Timer_Set(1000,onTimer,0);
  _do = GUIObject_GetDispObject((GUI*)List_Get(Find_StandbyBook()->xguilist->guilist,0));
  SIonRedraw=DispObject_GetOnRedraw(_do);
  ModifyKeyHook (WidgetKey,1);
  gc = get_DisplayGC();
  InitImages();
  DISP_DESC_SetOnRedraw(DispObject_GetDESC(_do),DISP_OnRedraw);
  return 0;
}
